import os
import sys
import re
import urllib
from datetime import datetime
from mimetypes import types_map
import logging
import wsgiref.handlers

from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from google.appengine.api import urlfetch
from google.appengine.api import users
from google.appengine.ext import db

sys.path = [os.path.dirname(__file__)] + sys.path

"""Load custom Django template filters"""
webapp.template.register_template_library('glog.template.tags')

import AppEnv
import base.RequestHandler
import base.Error
import base.Role
import base.Decorators
import models.Blog
import models.Post
import models.Comment
import models.Tag
import models.TrackBack
import models.Theme
import utils
import lib.PyRSS2Gen
import widgets

# the blogid_re to get blogid from self.reqpath
blogid_re = re.compile(r'/(?P<blogid>\w+)(?P<blogpath>(/.*)*)')

class GlogIndexPage(base.RequestHandler.PageRequestHandler):
    def get(self):
        extraPath = None
        if self.reqpath.startswith('/archive/'):
            #archive
            ar = self.reqpath[len('/archive/'):]
            m = re.match(r'(?P<year>\d{4})/(?P<month>\d{2})$',ar)
            if m:
                year = int(m.group('year'))
                month = int(m.group('month'))
                if month<1 or month >12:
                    self.renderErrorPage(base.Error.PageNotFoundError(),404)
                    return
                sdt = datetime(year,month,1)
                if month==12:
                    edt = datetime(year+1,1,1)
                else:
                    edt = datetime(year,month+1,1)
                posts = models.Post.Post.all().filter('published = ',True).filter('date >= ',sdt).filter('date < ',edt).order('-date').fetch(limit=100)
                extraPath = 'Archive:%04d-%02d' % (year, month)
            else:
                self.renderErrorPage(base.Error.PageNotFoundError(),404)
                return
        elif self.reqpath.startswith('/tag/'):
            #tag
            tag = self.reqpath[len('/tag/'):]
            tag = utils.urlString2PageString(tag)

            posts = models.Post.Post.all().filter('published = ',True).filter('tags = ',utils.toDBString(tag)).order('-date').fetch(limit=1000)
            extraPath = 'Tag:' + tag
            if not posts:
                self.renderErrorPage(base.Error.PageNotFoundError(),404)
                return
        else:
            posts = models.Post.Post.all().filter('published = ',True).order('-date').fetch(limit=self.appconfig.postsPerPage)

        # all archives
        arlist = models.Post.getArlist()

        # all tags
        taglist = models.Tag.getTaglist()

        # all blogs
        bloglist = models.Blog.Blog.all().fetch(limit=1000)
        
        if extraPath:
            self.templatedic['extraPath'] = extraPath
        self.templatedic['arlist'] = arlist
        self.templatedic['taglist'] = taglist
        self.templatedic['bloglist'] = bloglist
        self.templatedic['postlist'] = posts
        self.render(models.Theme.AppIndex_page)
        return

    def post(self):
        return self.get()
    
class GlogRssFeed(base.RequestHandler.PageRequestHandler):
    def get(self,*groups):
        fetcher = models.Post.Post.all().filter('published = ',True)
        tag = None
        if self.reqpath.startswith('/rss/tag/'):
            #tag
            tag = self.reqpath[len('/rss/tag/'):]
            tag = utils.urlString2PageString(tag)

            fetcher = fetcher.filter('tags = ',utils.toDBString(tag))
        
        posts = fetcher.order('-date').fetch(limit=self.appconfig.rssCount)

        rssItems = []
        for post in posts:
            post_url = '%s%s/%s/post/%s' % (self.appconfig.HostURL, self.apppath, post.blog.blogId, post.uid)
            rssItems.append(lib.PyRSS2Gen.RSSItem(
                    title = post.title,
                    author = utils.toPageString(post.blog.owner.nickname()),
                    link = post_url,
                    description = post.content,
                    pubDate = post.date,
                    guid = lib.PyRSS2Gen.Guid(post_url),
                    categories = post.tags
                    )
            )

        title = self.appname
        link = '%s%s' %  (self.appconfig.HostURL, self.apppath)
        if tag:
            title = title + ':' + utils.toPageString(tag)
            link = link + '/%s' % utils.pageString2UrlString(tag)
        rss = lib.PyRSS2Gen.RSS2(
                    title = title,
                    link = link,
                    description = 'latest %d posts of %s' % (min(len(rssItems), self.appconfig.rssCount), title),
                    lastBuildDate = datetime.utcnow(),
                    items = rssItems
                    )

        self.response.headers['Content-Type'] = 'application/rss+xml; charset=utf-8'
        self.write(rss.to_xml(encoding='utf-8'))           

class GlogCommentFeed(base.RequestHandler.PageRequestHandler):
    def get(self,*groups):
        fetcher = models.Comment.Comment.all()
        
        comments = fetcher.order('-date').fetch(limit=self.appconfig.rssCount)

        rssItems = []
        for comment in comments:
            post_url = '%s%s/%s/post/%s' % (self.appconfig.HostURL, self.apppath, comment.post.blog.blogId, comment.post.uid)
            comment_url = post_url + '#c%s' % comment.key().id()
            rssItems.append(lib.PyRSS2Gen.RSSItem(
                    title = comment.title,
                    author = utils.toPageString(comment.author.nickname()),
                    link = comment_url,
                    description = '%s reply to <a href="%s">%s</a>:<br/> %s' % (utils.toPageString(comment.author.nickname()),
                                                                                utils.toPageString(post_url),
                                                                                utils.toPageString(comment.post.title),
                                                                                utils.toPageString(comment.content)),
                    pubDate = comment.date,
                    guid = lib.PyRSS2Gen.Guid(comment_url),
                    )
            )

        title = self.appname
        link = '%s%s' %  (self.appconfig.HostURL, self.apppath)
        rss = lib.PyRSS2Gen.RSS2(
                    title = title,
                    link = link,
                    description = 'latest %d comments of %s' % (min(len(rssItems), self.appconfig.rssCount), title),
                    lastBuildDate = datetime.utcnow(),
                    items = rssItems
                    )

        self.response.headers['Content-Type'] = 'application/rss+xml; charset=utf-8'
        self.write(rss.to_xml(encoding='utf-8'))           
    
class PostList(base.RequestHandler.PageRequestHandler):
    @base.Decorators.blogRequest(blogid_re)
    def get(self):
        fetcher = models.Post.Post.all().filter('blog = ', self.blog).filter('published = ',True)
        if self.blogpath.startswith('/archive/'):
            #archive
            ar = self.blogpath[len('/archive/'):]
            m = re.match(r'(?P<year>\d{4})/(?P<month>\d{2})$',ar)
            if m:
                year = int(m.group('year'))
                month = int(m.group('month'))
                if month<1 or month >12:
                    self.renderErrorPage(base.Error.PageNotFoundError(),404)
                    return
                sdt = datetime(year,month,1)
                if month==12:
                    edt = datetime(year+1,1,1)
                else:
                    edt = datetime(year,month+1,1)
                posts = fetcher.filter('date >= ',sdt).filter('date < ',edt).order('-date').fetch(limit=100)
                extraPath = 'Archive:' + str(year) + '-' + str(month)
            else:
                self.renderErrorPage(base.Error.PageNotFoundError(),404)
                return
        elif self.blogpath.startswith('/tag/'):
            #tag
            tag = self.blogpath[len('/tag/'):]
            tag = utils.urlString2PageString(tag)
            posts = fetcher.filter('tags = ',utils.toDBString(tag)).order('-date').fetch(limit=1000)
            extraPath = 'Tag:' + tag
            if not posts:
                self.renderErrorPage(base.Error.PageNotFoundError(),404)
                return
        else:
            posts = fetcher.order('-date').fetch(limit=self.appconfig.postsPerPage)
            extraPath = None
        if extraPath:
            self.templatedic['extraPath'] = extraPath
        self.templatedic['postlist'] = posts
        self.render(models.Theme.PostList_page)
        return
    
class PostSummary(base.RequestHandler.PageRequestHandler):
    @base.Decorators.blogRequest(blogid_re)
    def get(self):
        curpage = 1
        if self.blogpath == '/summary':
            curpage = 1
        else:
            m = re.match(r'/summary/(?P<page>\d{1,4})$',self.blogpath)
            if m:
                curpage = int(m.group('page'))
            else:
                self.renderErrorPage(base.Error.PageNotFoundError(),404)
                return
        if self.is_blogowner:
            fetcher = models.Post.Post.all().filter('blog = ', self.blog).order('-date')
        else:
            fetcher = models.Post.Post.all().filter('blog = ', self.blog).filter('published = ',True).order('-date')

        posts = fetcher.fetch(limit=1000)

        if self.blog.postsPerPageList * curpage < 1 or self.blog.postsPerPageList * (curpage-1)>len(posts):
            self.renderErrorPage(base.Error.PageNotFoundError(),404)
            return
        else:
            prepage = curpage -1
            if self.blog.postsPerPageList * curpage >= len(posts):
                nextpage = 0
            else:
                nextpage = curpage + 1

        posts = fetcher.fetch(limit=self.blog.postsPerPageList, offset=self.blog.postsPerPageList*(curpage-1) )
            
        self.templatedic['postlist'] = posts
        self.templatedic['prepage'] = prepage
        self.templatedic['nextpage'] = nextpage
        self.render(models.Theme.PostSummary_page)
        return
        
class RssFeed(base.RequestHandler.PageRequestHandler):
    @base.Decorators.blogRequest(blogid_re)
    def get(self, *groups):
        fetcher = models.Post.Post.all().filter('blog = ', self.blog).filter('published = ',True)
        tag = None
        if self.blogpath.startswith('/rss/tag/'):
            #tag
            tag = self.blogpath[len('/rss/tag/'):]
            tag = utils.urlString2PageString(tag)

            fetcher = fetcher.filter('tags = ',utils.toDBString(tag))
        
        posts = fetcher.order('-date').fetch(limit=self.blog.rssCount)

        rssItems = []
        for post in posts:
            post_url = '%s%s/%s/post/%s' % (self.appconfig.HostURL, self.apppath, post.blog.blogId, post.uid)
            rssItems.append(lib.PyRSS2Gen.RSSItem(
                    title = post.title,
                    author = utils.toPageString(post.blog.owner.nickname()),
                    link = post_url,
                    description = post.content,
                    pubDate = post.date,
                    guid = lib.PyRSS2Gen.Guid(post_url),
                    categories = post.tags
                    )
            )

        title = self.blog.blogName
        link = '%s%s/%s' %  (self.appconfig.HostURL, self.apppath, self.blog.blogId)
        if tag:
            title = title + ':' + utils.toPageString(tag)
            link = link + '/%s' % utils.pageString2UrlString(tag)
        rss = lib.PyRSS2Gen.RSS2(
                    title = title,
                    link = link,
                    description = 'latest %d posts of %s' % (min(len(rssItems), self.blog.rssCount), title),
                    lastBuildDate = datetime.utcnow(),
                    items = rssItems
                    )

        self.response.headers['Content-Type'] = 'application/rss+xml; charset=utf-8'
        self.write(rss.to_xml(encoding='utf-8'))           

class CommentFeed(base.RequestHandler.PageRequestHandler):
    @base.Decorators.blogRequest(blogid_re)
    def get(self, *groups):
        uid = self.blogpath[len('/rss/comment/'):]
        if uid:
            # post
            uid = utils.urlString2uid(uid)

            posts = models.Post.Post.all().filter('uid = ',uid).fetch(limit=1)
            if not posts:
                self.renderErrorPage(base.Error.PageNotFoundError(),404)
                return
            post = posts[0]
            comments = [db.get(k)for k in post.comments[:self.appconfig.rssCount] ]
        else:
            comments = models.Comment.Comment.all().filter(' blog = ', self.blog).order('-date').fetch(limit=self.appconfig.rssCount)

        rssItems = []
        for comment in comments:
            post_url = '%s%s/%s/post/%s' % (utils.toPageString(self.appconfig.HostURL), self.apppath, utils.toPageString(comment.post.blog.blogId), comment.post.uid)
            comment_url = post_url + '#c%s' % comment.key().id()
            rssItems.append(lib.PyRSS2Gen.RSSItem(
                    title = utils.toPageString(comment.title),
                    author = utils.toPageString(comment.author.nickname()),
                    link = comment_url,
                    description = '%s reply to <a href="%s">%s</a>:<br/> %s' % (utils.toPageString(comment.author.nickname()),
                                                                                utils.toPageString(post_url),
                                                                                utils.toPageString(comment.post.title),
                                                                                utils.toPageString(comment.content)),
                    pubDate = comment.date,
                    guid = lib.PyRSS2Gen.Guid(comment_url),
                    )
            )

        if uid:
            # comments of a post
            title = 'Comments of %s' % utils.toPageString(post.title)
            link = '%s%s/%s/%s' % (self.appconfig.HostURL, self.apppath, self.blog.blogId, post.uid)
        else:
            # comment of the blog
            title = 'Comments of %s' % self.blog.blogName
            link = '%s%s/%s' %  (self.appconfig.HostURL, self.apppath, self.blog.blogId)
            
        rss = lib.PyRSS2Gen.RSS2(
                    title = title,
                    link = link,
                    description = 'latest %d comments of %s' % (min(len(rssItems), self.appconfig.rssCount), title),
                    lastBuildDate = datetime.utcnow(),
                    items = rssItems
                    )

        self.response.headers['Content-Type'] = 'application/rss+xml; charset=utf-8'
        self.write(rss.to_xml(encoding='utf-8'))           

class NewPost(base.RequestHandler.PageRequestHandler):
    @base.Decorators.blogRequest(blogid_re)
    @base.Decorators.needRole(base.Role.Blogowner)
    def get(self):
        self.render(models.Theme.EditPost_page)
        return

    @base.Decorators.blogRequest(blogid_re)
    @base.Decorators.needRole(base.Role.Blogowner)
    def post(self):
        user = users.get_current_user()

        errmsg = ''
        infomsg = ''
        uid = ''
        haserr = True
        while True:
            #references
            rfcount = int(self.param('referencecount'))
            rfs = []
            for i in range(rfcount):
                url = self.param('reference%d'%i)
                if url:
                    if not (url.startswith('http:') or url.startswith('https://')):
                        url = 'http://' + url
                    rfs.append(url)
            references = []            
            flag = False
            for i in range(rfcount):
                url = self.param('reference%d'%i)
                if url:                    
                    if not (url.startswith('http:') or url.startswith('https://')):
                        url = 'http://' + url
                    try:
                        references.append(db.Link(url))
                    except db.BadValueError,e:
                        errmsg = 'Reference "%s" is not a valid URL' % url
                        flag = True
                        break
            if flag:
                break
            #title
            title = self.param('title')
            title = utils.stripUnsafeTag(title)
            cr = models.Post.checkTitle(title)
            if not cr[0]:
                errmsg = cr[1]
                break
            #content
            content = self.param('content')
            content = utils.stripUnsafeTag(content)
            cr = models.Post.checkContent(content)
            if not cr[0]:
                errmsg = cr[1]
                break
            #published
            published = self.param('published') == '1'
            #tags
            tags = models.Tag.split_tags(utils.stripUnsafeTag(self.param('tags')))
            
            uid = models.Post.new_post(author=self.blog,
                                title=title,
                                content=content,
                                tags=tags,
                                references=references,
                                publish = published)

            if not published:
                infomsg = 'Post saved'
            haserr = False
            break
        if haserr or not published:
            self.templatedic['title'] = self.param('title')
            self.templatedic['uid'] = uid
            self.templatedic['content'] = self.param('content')
            self.templatedic['published'] = self.param('published') == '1'
            self.templatedic['referencelist'] = rfs
            self.templatedic['tags'] = models.Tag.split_tags(self.param('tags'))
            self.templatedic['errmsg'] = errmsg
            self.templatedic['infomsg'] = infomsg
            self.render(models.Theme.EditPost_page)
            return
        else:
            self.redirect('/blog/post/%s' % uid)
            
class EditPost(base.RequestHandler.PageRequestHandler):
    @base.Decorators.blogRequest(blogid_re)
    @base.Decorators.needRole(base.Role.Blogowner)
    def get(self):
        user = users.get_current_user()

        uid = self.blogpath[len('/edit/'):]
        uid = utils.urlString2uid(uid)

        posts = models.Post.Post.all().filter('uid = ',uid).fetch(limit=1)
        if not posts:
            self.renderErrorPage(base.Error.PageNotFoundError(),404)
            return
        else:
            post = posts[0]
            self.templatedic['title'] = post.title
            self.templatedic['uid'] = post.uid
            self.templatedic['content'] = post.content
            self.templatedic['published'] = post.published
            self.templatedic['referencelist'] = post.references
            self.templatedic['tags'] = post.tags
            self.templatedic['errmsg'] = ''
            self.render(models.Theme.EditPost_page)
            return

    @base.Decorators.blogRequest(blogid_re)
    @base.Decorators.needRole(base.Role.Blogowner)
    def post(self):
        user = users.get_current_user()

        errmsg = ''
        infomsg = ''
        haserr = True
        while True:
            #references
            rfcount = int(self.param('referencecount'))
            rfs = []
            for i in range(rfcount):
                url = self.param('reference%d'%i)
                if url:                    
                    if not (url.startswith('http:') or url.startswith('https://')):
                        url = 'http://' + url
                    rfs.append(url)
            references = []
            flag = False
            for i in range(rfcount):
                url = self.param('reference%d'%i)
                if url:                    
                    if not (url.startswith('http:') or url.startswith('https://')):
                        url = 'http://' + url
                    try:
                        references.append(db.Link(url))
                    except db.BadValueError,e:
                        errmsg = 'Reference "%s" is not a valid URL' % url
                        flag = True
                        break
            if flag:
                break
            #uid
            uid = self.param('uid')
                
            #title
            title = self.param('title')
            title = utils.stripUnsafeTag(title)
            cr = models.Post.checkTitle(title)
            if not cr[0]:
                errmsg = cr[1]
                break
            #content
            content = self.param('content')
            content = utils.stripUnsafeTag(content)
            cr = models.Post.checkContent(content)
            if not cr[0]:
                errmsg = cr[1]
                break
            #published
            published = self.param('published') == '1'
            #tags
            tags = models.Tag.split_tags(utils.stripUnsafeTag(self.param('tags')))

            try:
                models.Post.edit_post(blog=self.blog,
                               uid = uid,
                               title=title,
                               content=content,
                               tags=tags,
                               references=references,
                               publish=published)
            except base.Error.PageNotFoundError,e:
                self.renderErrorPage(e,404)
                return
            if not published:
                infomsg = 'Post saved'
            haserr = False
            break
        if haserr or not published:
            self.templatedic['title'] = self.param('title')
            self.templatedic['uid'] = self.param('uid')
            self.templatedic['content'] = self.param('content')
            self.templatedic['published'] = published
            self.templatedic['tags'] = models.Tag.split_tags(self.param('tags'))
            self.templatedic['errmsg'] = errmsg
            self.templatedic['infomsg'] = infomsg
            self.render(models.Theme.EditPost_page)
            return
        else:
            self.redirect('%s/%s/post/%s' % (AppEnv.app_root, self.blogid, uid))

class ViewPost(base.RequestHandler.PageRequestHandler):
    @base.Decorators.blogRequest(blogid_re)
    def get(self):
        uid = self.blogpath[len('/post/'):]
        uid = utils.urlString2uid(uid)
        posts = models.Post.Post.all().filter('blog = ', self.blog).filter('published = ',True).filter('uid = ',uid).fetch(limit=1)
        if posts:
            post = posts[0]
            commentList = []
            for comment in post.comments:
                commentList.append(db.get(comment))
            trackbacks = []
            for tb in post.trackbacks:
                trackbacks.append(db.get(tb))
            #pre and next post
            posts = models.Post.Post.all().filter('blog = ', self.blog).filter('published = ',True).filter('date < ',post.date).order('-date').fetch(limit=1)
            if posts:
                prepost = posts[0]
            else:
                prepost = None
            posts = models.Post.Post.all().filter('blog = ', self.blog).filter('published = ',True).filter('date > ',post.date).order('date').fetch(limit=1)
            if posts:
                nextpost = posts[0]
            else:
                nextpost = None
            self.templatedic['post'] = post
            self.templatedic['commentList'] = commentList
            self.templatedic['trackbacks'] = trackbacks
            self.templatedic['prepost'] = prepost
            self.templatedic['nextpost'] = nextpost
            self.render(models.Theme.ViewPost_page)
        else:
            self.renderErrorPage(base.Error.PageNotFoundError(),404)
            
class DeletePost(base.RequestHandler.PageRequestHandler):
    @base.Decorators.blogRequest(blogid_re)
    @base.Decorators.needRole(base.Role.Blogowner)
    def get(self):
        uid = self.blogpath[len('/del/'):]
        uid = utils.urlString2uid(uid)

        try:
            models.Post.delete_post(uid = uid)
        except base.Error.PageNotFoundError,e:
            self.renderErrorPage(e,404)
            return

        self.redirect('%s/%s' % (self.apppath, self.blogid))
            
class AddComment(base.RequestHandler.PageRequestHandler):
    @base.Decorators.blogRequest(blogid_re)
    @base.Decorators.needRole(base.Role.GUser)
    def post(self):
        user = users.get_current_user()
        
        uid = self.request.path[len('/blog/comment/'):]
        uid = utils.urlString2uid(uid)
        posts = models.Post.Post.all().filter('published = ',True).filter('uid = ',uid).fetch(limit=1)
        if posts:
            post = posts[0]
            haserr = True
            while True:
                title = self.param('title')
                title = utils.stripUnsafeTag(title)
                cr = models.Comment.checkTitle(title)
                if not cr[0]:
                    errmsg = cr[1]
                    break
                content = self.param('content')
                content = utils.stripUnsafeTag(content)
                cr = models.Comment.checkContent(content)
                if not cr[0]:
                    errmsg = cr[1]
                    break

                comment = models.Comment.add_comment(post, user, title, content)
                
                haserr = False
                break
            if haserr:
                self.renderErrorPage(errmsg)
                return
            self.redirect('/blog/post/%s' % uid)
        else:
            self.renderErrorPage(base.Error.PageNotFoundError(),404)

class TrackPost(base.RequestHandler.PageRequestHandler):
    @base.Decorators.blogRequest(blogid_re)
    def get(self):
        self.templatedic['errmsg'] = 'GET method is not supported for ping on this blog, use POST instead please.'
        self.render(models.Theme.FailedPingEcho_xml, default=True)
        return 
    
    @base.Decorators.blogRequest(blogid_re)
    def post(self):
        errmsg = ''

        uid = self.blogpath[len('/track/'):]
        uid = utils.urlString2uid(uid)
        posts = models.Post.Post.all().filter('blog = ', self.blog).filter('published = ',True).filter('uid = ',uid).fetch(limit=1)
        if posts:
            post = posts[0]
            while True:
                title = self.param('title')
                if len(title) > 200:
                    errmsg = 'invalid track back (%s)'%'title too long'
                    break
                blog_name = self.param('blog_name')
                if len(title) > 200:
                    errmsg = 'invalid track back (%s)'%'blog_name too long'
                    break
                try:
                    url = db.Link(self.param('url'))
                    tbs =  models.TrackBack.TrackBack.all().filter('post = ', post).filter(' url = ',url).fetch(limit=1)
                    if not tbs:
                        tb = models.TrackBack.TrackBack(post = post,
                                                        title = utils.toDBString(title),
                                                        blog_name = utils.toDBString(blog_name),
                                                        url = url)
                        tb.put()
                        post.trackbacks.append(tb.key())
                        post.put()
                    # FixMe TrackBack and Post should be n:m relatinship,
                    # here I assume a url ping only one post in our blog system(which is almost wrong).
                except db.BadValueError:
                    errmsg = 'invalid track back (%s)'%'bad url'
                
                break
        else:
            errmsg = 'Page Does not Exists(You want fool me?)'

        if errmsg:
            self.templatedic['errmsg'] = errmsg
            self.render(models.Theme.FailedPingEcho_xml, default=True)
            return
        else:
            self.render(models.Theme.SucceedPingEcho_xml, default=True)
            return 
    
class Settings(base.RequestHandler.PageRequestHandler):
    @base.Decorators.blogRequest(blogid_re)
    @base.Decorators.needRole(base.Role.Blogowner)
    def get(self):
        self.templatedic['blogName'] = self.blog.blogName
        self.templatedic['blogDesc'] = self.blog.blogDesc
        self.templatedic['postsPerPage'] = self.blog.postsPerPage
        self.templatedic['rssCount'] = self.blog.rssCount
        self.templatedic['postsPerPageList'] = self.blog.postsPerPageList
        self.templatedic['themename'] = self.blog.theme.name
        self.templatedic['themelist'] = models.Theme.getAllThemes()
        self.templatedic['widgets'] = '\n'.join(self.blog.widgets)
        self.render(models.Theme.Settings_page)
        return 

    @base.Decorators.blogRequest(blogid_re)
    @base.Decorators.needRole(base.Role.Blogowner)
    def post(self):
        #is reset?
        if self.param('submit') == 'reset':
            self.blog.reset()
            self.blog.put()
            self.templatedic['infomsg'] = 'Settings reset'
            self.templatedic['blogName'] = self.blog.blogName
            self.templatedic['blogDesc'] = self.blog.blogDesc
            self.templatedic['postsPerPage'] = self.blog.postsPerPage
            self.templatedic['rssCount'] = self.blog.rssCount
            self.templatedic['postsPerPageList'] = self.blog.postsPerPageList
            self.templatedic['themename'] = self.blog.theme.name
            self.templatedic['themelist'] = models.Theme.getAllThemes()
            self.templatedic['widgets'] = '\n'.join(self.blog.widgets)

            self.theme = self.blog.theme
            self.templatedic['theme'] = self.theme
            
            self.render(models.Theme.Settings_page)
            return 

        errmsg = ''
        infomsg = ''
        haserr = True
        while True:
            blogDesc = self.param('blogDesc')
            blogDesc = utils.stripUnsafeTag(blogDesc)

            blogName = self.param('blogName')
            blogName = utils.stripUnsafeTag(blogName)
            cr = models.Blog.checkblogName(blogName)
            if not cr[0]:
                errmsg = cr[1]
                break
                            
            postsPerPage = self.param('postsPerPage')
            cr = models.Blog.checkpostsPerPage(postsPerPage)
            if not cr[0]:
                errmsg = cr[1]
                break
            rssCount = self.param('rssCount')
            cr = models.Blog.checkrssCount(rssCount)
            if not cr[0]:
                errmsg = cr[1]
                break
            postsPerPageList = self.param('postsPerPageList')
            cr = models.Blog.checkpostsPerPageList(postsPerPageList)
            if not cr[0]:
                errmsg = cr[1]
                break
            # Theme
            themename = self.param('themename')
            theme = models.Theme.getTheme(themename)
            if not theme:
                errmsg = 'no this theme'
                break
            # widgets
            try:
                widgets = models.Blog.parseWidgets(self.param('widgets'))
            except base.Error.InvalidWidgetIdError,e:
                errmsg = str(e)
                break
            # API Password
            changeAPIPass = self.param('changeAPIPass')
            if changeAPIPass:
                apiPass = self.param('apiPass')
                cr = models.Blog.checkapiPass(apiPass)
                if not cr[0]:
                    errmsg = cr[1]
                    break
                apiPassag = self.param('apiPassag')
                if apiPass != apiPassag:
                    ermsg = 'Password is not the same.'
                    break
            try:
                self.blog.blogDesc = utils.toDBString(blogDesc)
                self.blog.blogName = utils.toDBString(blogName)
                self.blog.postsPerPage = int(postsPerPage)
                self.blog.rssCount = int(rssCount)
                self.blog.postsPerPageList = int(postsPerPageList)
                self.blog.widgets = widgets
                self.blog.theme = theme

                self.theme = theme
                self.templatedic['theme'] = theme
                # widgets
                models.Blog.attachWidgets(self.templatedic, self.blog.widgets)

                if changeAPIPass:
                    self.blog.setAPIPassword(apiPass)
                self.blog.put()
            except Exception,e:
                errmsg = str(e)
                break
            haserr = False
            infomsg = 'Setting saved.'
            break
        
        self.templatedic['errmsg'] = errmsg
        self.templatedic['infomsg'] = infomsg
        if haserr:
            self.templatedic['blogName'] = self.param('blogName')
            self.templatedic['blogDesc'] = self.param('blogDesc')
            self.templatedic['postsPerPage'] = self.param('postsPerPage')
            self.templatedic['rssCount'] = self.param('rssCount')
            self.templatedic['postsPerPageList'] = self.param('postsPerPageList')
            self.templatedic['changeAPIPass'] = self.param('changeAPIPass')
            self.templatedic['apiPass'] = self.param('apiPass')
            self.templatedic['apiPassag'] = self.param('apiPassag')
            self.templatedic['themename'] = self.param('themename')
            self.templatedic['themelist'] = models.Theme.getAllThemes()
            self.templatedic['widgets'] = self.param('widgets')
        else:
            self.templatedic['blogName'] = blogName
            self.templatedic['blogDesc'] = blogDesc
            self.templatedic['postsPerPage'] = postsPerPage
            self.templatedic['rssCount'] = rssCount
            self.templatedic['postsPerPageList'] = postsPerPageList
            self.templatedic['themename'] = theme.name
            self.templatedic['themelist'] = models.Theme.getAllThemes()
            self.templatedic['widgets'] = '\n'.join(widgets)
            if changeAPIPass:
                self.templatedic['changeAPIPass'] = changeAPIPass
                self.templatedic['apiPass'] = apiPass
                self.templatedic['apiPassag'] = apiPassag

        self.render(models.Theme.Settings_page)
        return
class GlogWidget(base.RequestHandler.PageRequestHandler):
    def get(self):
        wstr = self.reqpath[len('/widget/'):]
        return self.deal(wstr)

    def deal(self, wstr):
        w = wstr.split('/',1)
        if len(w) > 1:
            # has parameter
            wid = w[0]
            params = w[1].split('/')
        else:
            # no parameter
            wid = w[0]
            params = []

        self.dealWidget(wid, params)
        return
    
    def dealWidget(self, wid, params):
        wf = widgets.getWidget(wid)
        if wf and callable(wf):
            wf(self, params)
        else:
            raise base.Error.PageNotFoundError('no this widget [%s]' % wid)

        self.render(wid + ".widget")
        return

class BlogWidget(GlogWidget):
    @base.Decorators.blogRequest(blogid_re)
    def get(self):
        wstr = self.blogpath[len('/widget/'):]
        return self.deal(wstr)
    pass

    
def main():
    application = webapp.WSGIApplication(
                           [
                            (AppEnv.apppath + '/?', GlogIndexPage),
                            (AppEnv.apppath + '/archive/.+', GlogIndexPage),
                            (AppEnv.apppath + '/tag/.+', GlogIndexPage),
                            (AppEnv.apppath + '/rss/comment(/.*)*', GlogCommentFeed),
                            (AppEnv.apppath + '/rss(/.*)*', GlogRssFeed),
                            (AppEnv.apppath + '/widget/.+', GlogWidget),
                            (AppEnv.apppath + '/\w+/?',PostList ),
                            (AppEnv.apppath + '/\w+/summary', PostSummary),
                            (AppEnv.apppath + '/\w+/summary/.*', PostSummary),
                            (AppEnv.apppath + '/\w+/new/?', NewPost),
                            (AppEnv.apppath + '/\w+/edit', EditPost),
                            (AppEnv.apppath + '/\w+/edit/.+', EditPost),
                            (AppEnv.apppath + '/\w+/post/.+',ViewPost),
                            (AppEnv.apppath + '/\w+/del/.+', DeletePost),
                            (AppEnv.apppath + '/\w+/comment/.+', AddComment),
                            (AppEnv.apppath + '/\w+/archive/.+', PostList),
                            (AppEnv.apppath + '/\w+/tag/.+', PostList),
                            (AppEnv.apppath + '/\w+/rss/comment(/.*)*', CommentFeed),
                            (AppEnv.apppath + '/\w+/rss(/.*)*', RssFeed),
                            (AppEnv.apppath + '/\w+/track/.+', TrackPost),
                            (AppEnv.apppath + '/\w+/settings', Settings),
                            (AppEnv.apppath + '/\w+/widget/.+', BlogWidget),
                            ('.*', base.RequestHandler.HTTP404),
                            ],
                           debug=AppEnv.debug)
    wsgiref.handlers.CGIHandler().run(application)

if __name__ == '__main__':
    main()

